import java.util.*;

/**
 * Classe para demonstrar o Estado do Aspirador.
 * 
 * @author Gabriel Soares
 */
public class EstadoAspirador {

	int roboX = 0, roboY = 0;
	int intNumCol = 7, intNumLin = 7;
	int[][] estado = new int[intNumLin][intNumCol];
	int iQuantoFalta = 0;
	Acao acaoExecutada = null;

	/**
	 * Carrega as acoes possiveis.
	 * 
	 * @return Lista de Acoes.
	 */
	List<Acao> acoesPossiveis() {

		List<Acao> retorno = new ArrayList<Acao>();

		// Mover esquerda.
		if (roboX > 0 && roboX <= intNumLin - 1) {
			retorno.add(new Acao(1));
		}
		// Mover direita.
		if (roboX >= 0 && roboX < intNumLin - 1) {
			retorno.add(new Acao(2));
		}
		// Mover abaixo.
		if (roboY >= 0 && roboY < intNumCol - 1) {
			retorno.add(new Acao(4));
		}
		// Mover cima.
		if (roboY > 0 && roboY <= intNumCol - 1) {
			retorno.add(new Acao(3));
		}
		// Limpar.
		if (estado[roboX][roboY] == 1)
			retorno.add(new Acao(5));

		return retorno;
	}

	/**
	 * Executa uma acao.
	 * 
	 * @param a
	 *            Acao a ser executada
	 * @return O estado apos a acao ser realizada.
	 */
	EstadoAspirador executaAcao(Acao a) {

		EstadoAspirador novoEstado = new EstadoAspirador();

		novoEstado.estado = Util.copiaMatrix(this.estado);
		novoEstado.roboX = this.roboX;
		novoEstado.roboY = this.roboY;

		if (a.movimento[2] == 1) {
			novoEstado.estado[roboX][roboY] = 0;
		} else {
			novoEstado.roboX += a.movimento[0];
			novoEstado.roboY += a.movimento[1];
		}

		verificaEstadoFinal();

		return novoEstado;
	}

	/**
	 * Verifica se o estado final foi alcancado.
	 * 
	 * @return True se sim, senão False.
	 */
	boolean verificaEstadoFinal() {

		boolean verifica = true;
		iQuantoFalta = 0;

		for (int i = 0; i < intNumCol; i++) {
			for (int j = 0; j < intNumLin; j++) {
				if (estado[i][j] == 1) {
					verifica = false;
					iQuantoFalta += 1;
				}
			}
		}

		return verifica;
	}

	/**
	 * Gera um Estado Inicial Aleatório.
	 * 
	 * @return Objeto EstadoAspirador com um estado criado.
	 */
	static EstadoAspirador geraEstadoInicialAleatorio() {

		EstadoAspirador novoEstado = new EstadoAspirador();

		for (int i = 0; i < novoEstado.intNumLin; i++) {
			for (int j = 0; j < novoEstado.intNumCol; j++) {
				novoEstado.estado[i][j] = (int) (Math.random() * 2);
			}
		}

		novoEstado.roboX = 0;
		novoEstado.roboY = 0;

		return novoEstado;

	}

	public ArrayList<EstadoAspirador> resolveAspirador() {
		ArrayList<EstadoAspirador> retorno = new ArrayList<EstadoAspirador>();
		ArrayList<EstadoAspirador> escolheEstado = new ArrayList<EstadoAspirador>();

		EstadoAspirador resolve = new EstadoAspirador();
		resolve.estado = Util.copiaMatrix(this.estado);
		resolve.roboX = this.roboX;
		resolve.roboY = this.roboY;

		while (true) {

			for (Acao a : resolve.acoesPossiveis()) {
				EstadoAspirador novoEstado = resolve.executaAcao(a);
				novoEstado.verificaEstadoFinal();
				novoEstado.acaoExecutada = a;
				escolheEstado.add(novoEstado);
			}

			if (!escolheEstado.isEmpty()) {
				for (int i = 0; i < escolheEstado.size(); i++) {
					if (!verificaEstadoVisitado(escolheEstado.get(i), retorno)){
						resolve = escolheEstado.get(i);
						if (escolheEstado.get(i).iQuantoFalta < resolve.iQuantoFalta )
							resolve = escolheEstado.get(i);
					}
				}

				retorno.add(resolve);
				escolheEstado.clear();

				if (resolve.verificaEstadoFinal())
					break;
			} else
				break;

		}

		return retorno;
	}

	private boolean verificaEstadoVisitado(EstadoAspirador estadoAspirador,
			ArrayList<EstadoAspirador> retorno) {
		for(int i = 0; i < retorno.size(); i++){
			if(retorno.get(i).roboX == estadoAspirador.roboX && retorno.get(i).roboY == estadoAspirador.roboY && estadoAspirador.acaoExecutada.movimento[2] != 1)
				return true;
		}
		return false;
	}

}
